package club.kingyin.context;

import club.kingyin.annotation.Autowired;
import club.kingyin.annotation.Value;
import club.kingyin.core.*;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author : kingyins
 * @version : 1.0
 * @program : my-spring
 * @description : 在此处添加类描述
 * @create : 2021年07月16日 15:26
 **/
public abstract class AbstractApplicationContext implements BeanFactory, BeanFactoryPostProcess {


    /** 单例池 （一级缓存）暂时不考虑循环依赖的问题 */
    private Map<String, Object> singletons = new ConcurrentHashMap<>(16);

    /** 后置处理器集合 */
    protected Set<BeanPostProcessor> beanPostProcessorSet = new HashSet<>();

    /** bean定义信息注册器 **/
    private BeanDefinitionRegistry beanDefinitionRegistry;

    /** BeanFactory处理器 **/
    private BeanFactoryPostProcess beanFactoryPostProcess;

    public void setBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        this.beanDefinitionRegistry = registry;
    }

    /**
     * 预先处理
     */
    protected void prepareRefresh() {
        System.out.println("预处理");
    }

    /**
     * 注册BeanFactory后置处理器预处理
     * @param beanFactoryPostProcess 后置处理器
     */
    protected void prepareBeanFactory(BeanFactoryPostProcess beanFactoryPostProcess) {
        this.beanFactoryPostProcess = beanFactoryPostProcess;
    }

    /**
     * 调用BeanFactory后置处理器
     */
    protected void invokeBeanFactoryPostProcessors() {
        if (beanFactoryPostProcess != null) {
            beanFactoryPostProcess.postProcessBeanFactory(this);
        }
    }

    /**
     * 注册Bean后置处理器
     */
    protected abstract void registerBeanPostProcessors();


    /**
     * 注册beanDefinition
     * @param beanDefinition mbd
     */
    public void registerBeanDefinition(BeanDefinition beanDefinition) {
        beanDefinitionRegistry.register(beanDefinition.getBeanClassName(), beanDefinition);
    }


    @Override
    public Object getBean(String beanName) {
        // 从单例池获得
        Object o = singletons.get(beanName);
        if (o == null) {
            // 没有则尝试创建bean
            o = createBean(beanName);
        }
        return o;
    }

    @Override
    public <T> T getBean(String beanName, Class<T> beanClassType) {
        return beanClassType.cast(getBean(beanName));
    }

    /**
     * 判断某个Class 的 BeanDefinition 是否存在
     * @param classType class
     * @return 布尔
     */
    protected boolean containsBeanClass(Class<?> classType) {
        // 调用注册器的方法判断
        return beanDefinitionRegistry.containsBeanClass(classType);
    }

    protected Object createBean(String beanName) {
        // 获取bean定义
        BeanDefinition beanDefinition = beanDefinitionRegistry.get(beanName);
        if (beanDefinition == null) {
            // 没有对应的bean定义
            throw new RuntimeException("没有找到对应的BeanDefinition '"+beanName+"'");
        }

        // 真正的创建bean
        return doCreateBean(beanDefinition, beanName);
    }

    protected Object doCreateBean(BeanDefinition mbd, String beanName) {

        // 实例化前置增强器
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorSet) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
                 ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessorBeforeInstantiation(mbd,beanName);
            }
        }

        // 实例化
        Object instantiation = null;
        try {
            System.out.println(beanName+"实例化中...");
            instantiation = instantiation(mbd.getBeanClass(), beanName);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 实例化后置处理器
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorSet) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
                ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessorAfterInstantiation(instantiation,beanName);
            }
        }

        // 属性填充(包括自动注入和其他属性填充)
        try {
            if (instantiation == null) {
                throw new RuntimeException("实例化失败 '"+beanName+"'");
            }
            System.out.println("属性填充中...");
            propertiesSet(instantiation);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        // Aware回调
        if (instantiation instanceof BeanNameAware) {
            ((BeanNameAware)instantiation).setBeanName(beanName);
        }

        // 初始化前置处理器
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorSet) {
            if (!(beanPostProcessor instanceof InstantiationAwareBeanPostProcessor)) {
                beanPostProcessor.PostProcessorBeforeInitialization(instantiation,beanName);
            }
        }

        // 初始化bean
        if (instantiation instanceof InitializingBean) {
            System.out.println(beanName+"初始化中...");
            ((InitializingBean) instantiation).afterPropertiesSet();
        }

        // 初始化后置处理器
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorSet) {
            if (!(beanPostProcessor instanceof InstantiationAwareBeanPostProcessor)) {
                beanPostProcessor.PostProcessorAfterInitialization(instantiation,beanName);
            }
        }

        // 是单例 则放入单例池中
        if (Scope.SINGLETON == mbd.getScope()) {
            singletons.put(beanName, instantiation);
        }

        return instantiation;
    }

    /**
     * 实例化bean
     * @return 一个空的bean
     */
    protected <T>T instantiation(Class<T> classType, String beanName) throws IllegalAccessException, InvocationTargetException, InstantiationException {
        Constructor<?>[] ctors = classType.getDeclaredConstructors();
        T instance = null;
        for (Constructor<?> ctor : ctors) {
            Class<?>[] parameterTypes = ctor.getParameterTypes();
            // 暂时只选择无参构造
            if (parameterTypes.length == 0) {
                instance = classType.cast(ctor.newInstance());
            }
        }
        if (instance == null) {
            throw new RuntimeException("没有合适的构造器 '"+beanName+"'");
        }

        return instance;
    }

    /**
     * 属性填充
     * @param bean 空的bean
     * @return 填充属性后的bean
     */
    protected Object propertiesSet(Object bean) throws IllegalAccessException {
        // 获得所有属性
        Field[] fields = bean.getClass().getDeclaredFields();
        for (Field field : fields) {
            // 自动注入
            if (field.isAnnotationPresent(Autowired.class)) {
                Class<?> type = field.getType();
                // 存在
                if (containsBeanClass(type)) {
                    field.setAccessible(true);
                    // 注入流程
                    field.set(bean, getBean(field.getName(), type));
                    continue;
                } else {
                    throw new RuntimeException("注入失败没有该实例 '"+field.getName()+"'");
                }
            }
            // 注入其他属性
            if (field.isAnnotationPresent(Value.class)) {
                Class<?> type = field.getType();
                field.setAccessible(true);

                Value annotation = field.getAnnotation(Value.class);
                String value = annotation.value();
                if (int.class.equals(type)) {
                    field.set(bean, Integer.valueOf(value));
                } else if (String.class.equals(type)) {
                    field.set(bean, value);
                } else if (double.class.equals(type)) {
                    field.set(bean, Double.valueOf(value));
                } else if (boolean.class.equals(type)) {
                    field.set(bean, Boolean.valueOf(value));
                } else if (float.class.equals(type)) {
                    field.set(bean, Float.valueOf(value));
                } else if (char.class.equals(type)) {
                    field.set(bean, value.charAt(0));
                } else if (short.class.equals(type)) {
                    field.set(bean, Short.valueOf(value));
                }

            }
        }
        return bean;
    }

    public void refresh() {

        // 预处理
        prepareRefresh();

        // 预处理后置处理
        postProcessBeanFactory();

        // 调用BeanFactory后置处理器
        invokeBeanFactoryPostProcessors();

        // 注册Bean后置处理器
        registerBeanPostProcessors();

        // 创建Bean
        finishBeanFactoryInitialization();

        // 创建完成
        finishRefresh();

    }

    private void finishBeanFactoryInitialization() {
        // 全部创建
        beanDefinitionRegistry.get().keySet().forEach(this::getBean);
    }

    private void finishRefresh() {

    }

    public void postProcessBeanFactory() {

    }
}
